package com.ruicar.afs.cloud.image.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.Img;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruicar.afs.cloud.common.core.security.util.SecurityUtils;
import com.ruicar.afs.cloud.image.condition.AuditCondition;
import com.ruicar.afs.cloud.image.condition.ImageCondition;
import com.ruicar.afs.cloud.image.condition.ShowFileCondition;
import com.ruicar.afs.cloud.image.config.FileProperties;
import com.ruicar.afs.cloud.image.config.GwtFastdfsProperties;
import com.ruicar.afs.cloud.image.entity.ComAttachmentFile;
import com.ruicar.afs.cloud.image.entity.ComAttachmentManagement;
import com.ruicar.afs.cloud.image.enums.*;
import com.ruicar.afs.cloud.image.mapper.ComAttachmentFileMapper;
import com.ruicar.afs.cloud.image.service.ComAttachmentFileService;
import com.ruicar.afs.cloud.image.store.enums.IsViewEnum;
import com.ruicar.afs.cloud.image.store.feign.ImageStoreApiFeign;
import com.ruicar.afs.cloud.image.util.ImageUtil;
import com.ruicar.afs.cloud.image.vo.AuditFileDetailsVo;
import com.ruicar.afs.cloud.image.vo.AuditFileStatusVo;
import com.ruicar.afs.cloud.image.vo.AuditFileVo;
import com.ruicar.afs.cloud.image.vo.UploadInputVo;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriComponentsBuilder;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 通用附件表
 * @Author: fangchenliang
 * @Date: 2020/6/4 19:50
 */
@AllArgsConstructor
@Service
@Slf4j
public class ComAttachmentFileServiceImpl extends ServiceImpl<ComAttachmentFileMapper, ComAttachmentFile> implements ComAttachmentFileService {

    private GwtFastdfsProperties gwtFastdfsProperties;
    private ImageStoreApiFeign imageStoreApiFeign;
    private final ImageUtil imageUtil;
    private FileProperties fileProperties;

    /**
     * 获取token信息
     *
     * @return
     */
    public String getAuthorization() {
        Map<String, String> data = new HashMap<>();
        data.put("client_id", gwtFastdfsProperties.getClientId());
        data.put("client_secret", gwtFastdfsProperties.getClientSecret());
        data.put("grant_type", gwtFastdfsProperties.getGrantType());
        JSONObject jsonObject = imageStoreApiFeign.getTokenInfo(data);
        String authorization = jsonObject.getString("token_type") + " " + jsonObject.getString("access_token");
        return authorization;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation("修改附件文件状态")
    public ComAttachmentFile updateFileStatus(AuditFileStatusVo vo) {
        ComAttachmentFile file = this.getById(vo.getId());
        Assert.isTrue(file != null, "附件不存在!");
        if (!file.getFileStatus().equals(vo.getFileStatus())) {
            file.setFileStatus(vo.getFileStatus());
            this.updateById(file);
        }
        return file;
    }

    @Override
    public List<ComAttachmentFile> getDealerSign(String applyNo) {


        return null;
    }


    /**
     * @Description:
     * @Author: fangchenliang
     * @Date: 2020/6/5 14:56
     * @Param: [busiNo, busiNode]
     * @Return: java.util.List<com.ruicar.afs.cloud.image.entity.ComAttachmentFile>
     */
    @Override
    public List<ComAttachmentFile> findUploadFileByBusiNo(String busiNo, List busiNodes) {
        return baseMapper.findUploadFileByBusiNo(busiNo, busiNodes);
    }

    @Override
    public ComAttachmentFile saveComAttachmentFile(UploadInputVo uploadInputVo) {
        /**保存影像件相关信息合同信息*/
        List<String> statuslist=new ArrayList<>();
        statuslist.add(FileStatusEnum.DRAFT.getCode());//草稿
        statuslist.add(FileStatusEnum.STANDARD.getCode());//合格
        ComAttachmentFile comAttachmentFile = this.getOne(Wrappers.<ComAttachmentFile>lambdaQuery()
                .eq(ComAttachmentFile::getFileId, uploadInputVo.getFileMd5())
                .eq(ComAttachmentFile::getBusiNo, uploadInputVo.getBusiNo())
                .eq(ComAttachmentFile::getBelongNo, uploadInputVo.getBelongNo())
                .eq(ComAttachmentFile::getAttachmentCode, uploadInputVo.getAttachmentId())
                .in(ComAttachmentFile::getFileStatus,statuslist), false);
        if (comAttachmentFile == null) {
            comAttachmentFile = ComAttachmentFile.convertFrom(new ComAttachmentFile(), uploadInputVo);
            comAttachmentFile.setFileStatus(FileStatusEnum.DRAFT.getCode());
            comAttachmentFile.setIsElectronic(IsElectronicEnum.NO.getCode());
            //最新版本默认为0
            comAttachmentFile.setHistoryVersion("0");
            comAttachmentFile.setArchiveClass(uploadInputVo.getArchiveClass());
            comAttachmentFile.setFileSource(uploadInputVo.getFileSource());
            this.baseMapper.insert(comAttachmentFile);
        } else {
            comAttachmentFile = ComAttachmentFile.convertFrom(comAttachmentFile, uploadInputVo);
            comAttachmentFile.setFileStatus(FileStatusEnum.DRAFT.getCode());
            comAttachmentFile.setIsElectronic(IsElectronicEnum.NO.getCode());
            comAttachmentFile.setHistoryVersion("0");
            comAttachmentFile.setArchiveClass(uploadInputVo.getArchiveClass());
            comAttachmentFile.setFileSource(uploadInputVo.getFileSource());
            this.baseMapper.updateById(comAttachmentFile);
        }
        return comAttachmentFile;
    }

    /**
     * @Description: 文件合成之后上传文件至OSS
     * @Author: fangchenliang
     * @Date: 2020/6/28 13:46
     * @Param: [file, uploadInputVo]
     * @Return: void
     */
    public ComAttachmentFile storeFileToOss(File file, UploadInputVo uploadInputVo) {

        ComAttachmentFile comAttachmentFile = null;
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", getAuthorization());
        MultipartFile mfile = imageUtil.getMulFile(file, uploadInputVo.getFileName());
        JSONObject resultJson = imageStoreApiFeign.storeFile( gwtFastdfsProperties.getSceneId(), null, mfile, headers);
        Boolean requestOK = resultJson.containsKey("success") && resultJson.getInteger("success") == ResultCodeEnum.SUCCESS.getCode();
        if (requestOK) {
            JSONObject resultData = resultJson.containsKey("data") ? resultJson.getJSONObject("data") : new JSONObject();
            Boolean uploadOK = resultData.containsKey("success") && resultData.getBoolean("success");
            if (uploadOK) {
                log.info("文件-" + uploadInputVo.getFileName() + "：上传成功！");
                String md5Value = resultData.containsKey("md5") ? resultData.getString("md5") : "";
                // modify by limingzhi 20200915
                if(IsDeleteEnum.YES.getCode().equals(uploadInputVo.getIsDelete())){
                    List<ComAttachmentFile> fileList = this.list(Wrappers.<ComAttachmentFile>query().lambda()
                            .eq(ComAttachmentFile::getBusiNo, uploadInputVo.getBusiNo())
                            .eq(ComAttachmentFile::getBelongNo, uploadInputVo.getBelongNo())
                            //.eq(ComAttachmentFile::getFileId, md5Value)
                            .eq(ComAttachmentFile::getAttachmentCode, uploadInputVo.getAttachmentId()));
                    if (fileList.size() > 0) {
                        fileList.forEach(cfile -> {
                            this.removeById(cfile);
                        });
                    }
                }
                comAttachmentFile = new ComAttachmentFile();
                comAttachmentFile.setAttachmentCode(uploadInputVo.getAttachmentId());
                comAttachmentFile.setFileName(uploadInputVo.getFileName());
                comAttachmentFile.setAttachmentName(uploadInputVo.getAttachmentName());
                comAttachmentFile.setBusiNo(uploadInputVo.getBusiNo());
                comAttachmentFile.setBelongNo(uploadInputVo.getBelongNo());
                comAttachmentFile.setFileId(md5Value);
                comAttachmentFile.setFileType(uploadInputVo.getFileType());
                comAttachmentFile.setFileStatus(uploadInputVo.getFileStatus()==null?FileStatusEnum.STANDARD.getCode():uploadInputVo.getFileStatus());
                comAttachmentFile.setUploadTime(new Date());
                comAttachmentFile.setFileSource(uploadInputVo.getFileSource());
                comAttachmentFile.setIsElectronic(uploadInputVo.getIsElectronic());
                comAttachmentFile.setHistoryVersion(uploadInputVo.getFileVersion()==null?"0":uploadInputVo.getFileVersion());
                comAttachmentFile.setArchiveClass(uploadInputVo.getArchiveClass());
                this.save(comAttachmentFile);
            }
        }
        return comAttachmentFile;
    }

    /**
     * 获取远端文件数据
     */
    @Override
    public byte[] getComAttachmentFile(@Validated UploadInputVo vo) {

        // 1. 查询附件对象
        List<ComAttachmentFile> fileList = list(Wrappers.<ComAttachmentFile>query().lambda()
                .eq(ComAttachmentFile::getAttachmentCode, vo.getAttachmentId())
                .eq(ComAttachmentFile::getBusiNo, vo.getBusiNo())
                .eq(ComAttachmentFile::getBelongNo, vo.getBelongNo())
                .orderByDesc(ComAttachmentFile::getUploadTime));
        Assert.isTrue(CollUtil.isNotEmpty(fileList), "获取远端模板数据失败，请检查用来获取远端模板的参数");
        ComAttachmentFile file = fileList.get(0);
        // 2. 从远端接口获取数据
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", getAuthorization());
        byte[] fileByte = imageStoreApiFeign.downFile(file.getFileId(), gwtFastdfsProperties.getSceneId(), file.getFileName(), IsViewEnum.download.getCode(), null, headers);
        return fileByte;
    }

    @Override
    public List<AuditFileVo> getAllFileList(AuditCondition auditCondition) {
        List list = Arrays.asList(auditCondition.getBusiNodes().split(","));
        auditCondition.setList(list);
        List<AuditFileVo> auditFileVos = this.baseMapper.getAuditFileVoList(auditCondition);
        auditFileVos.forEach(auditFileVo -> {
            //获取当前用户
            boolean attachmentStatus=true;
            auditFileVo.setUserId(SecurityUtils.getUsername());
            auditFileVo.setViewTime(DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));
            //查询附件信息
            List<String> version=new ArrayList<>();
            if(ObjectUtils.isNotEmpty(auditCondition.getHistoryVersion())){
                if(!auditCondition.getHistoryVersion().equals("all")){
                    version.add("0");
                    version.add(auditCondition.getHistoryVersion()) ;
                }
            }
            List<ComAttachmentFile> listVo = this.list(Wrappers.<ComAttachmentFile>query().lambda()
                    .eq(ComAttachmentFile::getAttachmentCode, auditFileVo.getAttachmentCode())
                    .eq(ComAttachmentFile::getBusiNo, auditCondition.getBusiNo())
                    .eq(ComAttachmentFile::getBelongNo, auditCondition.getBelongNo())
                    .in(!CollectionUtils.isEmpty(version),ComAttachmentFile::getHistoryVersion, version));
            for(ComAttachmentFile detailsVovo:listVo){
                if(detailsVovo.getFileStatus().equals(FileStatusEnum.NOTSTANDARD.getCode())){
                    attachmentStatus=false;
                }
            }
            auditFileVo.setFileList(listVo);
            auditFileVo.setAttachmentStatus(attachmentStatus);
        });
        return auditFileVos;
    }

    @Override
    public ComAttachmentManagement downloadFileByType(String applyNo, String belongNo, String typeData) {
        JSONObject jsonObject = JSONObject.parseObject(typeData);
        ComAttachmentManagement comAttachmentManagement = (ComAttachmentManagement) JSONObject.toJavaObject(jsonObject, ComAttachmentManagement.class);
        List<ComAttachmentFile> fileList = null;
        if (comAttachmentManagement.getAttachmentClass() == AttachmentClassEnum.SUBCLASS.getCode()) {
            fileList = this.list(Wrappers.<ComAttachmentFile>query().lambda()
                    .eq(ComAttachmentFile::getAttachmentCode, String.valueOf(comAttachmentManagement.getId()))
                    .eq(ComAttachmentFile::getBusiNo, applyNo)
                    .eq(ComAttachmentFile::getBelongNo, belongNo)
                    .eq(ComAttachmentFile::getHistoryVersion, "0"));//获取当前最新的附件，不获取历史版本。
        }
        List<ComAttachmentFile> cmList = new ArrayList<ComAttachmentFile>();
        if (fileList != null && fileList.size() > 0) {
            for (ComAttachmentFile image : fileList) {
                if (StringUtils.isNotEmpty(image.getFileId())) {
                    URI url = getUrlFromArrayMap(image.getFileId(), image.getFileName(), IsViewEnum.view.getCode());
                    image.setImageUrl(url.toString());
                    image.setThumUrl(url.toString());
                    cmList.add(image);
                }
            }
        }
        comAttachmentManagement.setFileList(cmList);
        comAttachmentManagement.setAuthorization(getAuthorization());
        return comAttachmentManagement;
    }

    @Override
    public ComAttachmentManagement showFileByType(ShowFileCondition showFileCondition) {
        String busiNo=showFileCondition.getBusiNo();
        String belongNo=showFileCondition.getBelongNo();
        ComAttachmentManagement comAttachmentManagement = showFileCondition.getComAttachmentManagement();
        List<ComAttachmentFile> fileList = null;
        if (comAttachmentManagement.getAttachmentClass() == AttachmentClassEnum.SUBCLASS.getCode()) {
            fileList = this.list(Wrappers.<ComAttachmentFile>query().lambda()
                    .eq(ComAttachmentFile::getAttachmentCode, String.valueOf(comAttachmentManagement.getId()))
                    .eq(ComAttachmentFile::getBusiNo, busiNo)
                    .eq(ComAttachmentFile::getBelongNo, belongNo)
                    .eq(ComAttachmentFile::getHistoryVersion, "0"));//获取当前最新的附件，不获取历史版本。
        }
        List<ComAttachmentFile> cmList = new ArrayList<ComAttachmentFile>();
        if (fileList != null && fileList.size() > 0) {
            for (ComAttachmentFile image : fileList) {
                if (StringUtils.isNotEmpty(image.getFileId())) {
                    URI url = getUrlFromArrayMap(image.getFileId(), image.getFileName(), IsViewEnum.view.getCode());
                    image.setImageUrl(url.toString());
                    image.setThumUrl(url.toString());
                    cmList.add(image);
                }
            }
        }
        comAttachmentManagement.setFileList(cmList);
        comAttachmentManagement.setAuthorization(getAuthorization());
        return comAttachmentManagement;
    }

    //组装路径
    private URI getUrlFromArrayMap(String md5, String filename, String isview) {
        Map<String, Object> params = new HashMap<>();
        params.put("md5", md5);
        params.put("downloadsceneid", gwtFastdfsProperties.getSceneId());
        params.put("filename", filename);
        params.put("is_view", isview);
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(gwtFastdfsProperties.getUrl() + "/S120017/v2/download");
        if (params != null) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                uriComponentsBuilder.queryParam(entry.getKey(), entry.getValue());
            }
        }
        return uriComponentsBuilder.build().toUri();
    }

    /**
     * 通过id下载合同影像资料
     *
     * @param attachmentFile
     * @return
     */
    public byte[] downloadAttachmentFile(ComAttachmentFile attachmentFile) {

        Assert.isTrue(attachmentFile != null, "合同模板不存在，请联系管理员！");
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", getAuthorization());
        byte[] fileByte = imageStoreApiFeign.downFile(attachmentFile.getFileId(),  gwtFastdfsProperties.getSceneId(), attachmentFile.getFileName(), IsViewEnum.download.getCode(), null, headers);
        return fileByte;
    }

    /**获取影像件历史版本号
     * @Description:
     * @Author: fangchenliang
     * @Date: 2020/8/2 15:58
     * @Param:
     * @Return:
     */
    public List<String> getHistoryVersion(String busiNo,String busiNode,String attachmentCode){
        List<String> versionList = this.baseMapper.getHistoryVersion(busiNo, busiNode,attachmentCode);
        return versionList;
    }

    /**
     * @Description:提交业务修改初始文件状态为合格
     * @Author: fangchenliang
     * @Date: 2020/8/2 18:48
     * @Param:[busiNo]
     * @Return:
     */
    public void updateFileStatusByBusiNo(String busiNo){
        List<ComAttachmentFile> fileList=this.list(Wrappers.<ComAttachmentFile>query().lambda()
                .eq(ComAttachmentFile::getBusiNo,busiNo)
                .eq(ComAttachmentFile::getFileStatus,FileStatusEnum.DRAFT.getCode()));
        fileList.forEach(file->{
            file.setFileStatus(FileStatusEnum.STANDARD.getCode());
            this.updateById(file);
        });
    }

    /**
     * @Description: 进件提交修改文件版本
     * @Author: fangchenliang
     * @Date: 2020/8/2 19:01
     * @Param: [busiNo]
     * @Return: void
     */
    public void updateFileVersionByBusiNo(String busiNo,String busiNode){
        /**获取新上传的文件*/
        List<ComAttachmentFile> newFileList=this.list(Wrappers.<ComAttachmentFile>query().lambda()
                .eq(ComAttachmentFile::getBusiNo,busiNo)
                .eq(ComAttachmentFile::getHistoryVersion,"0")
                .eq(ComAttachmentFile::getFileStatus,FileStatusEnum.DRAFT.getCode()));
        Map<String, List<ComAttachmentFile>> newlistMap=newFileList.stream().collect(Collectors.groupingBy(ComAttachmentFile::getAttachmentCode));
        newlistMap.forEach((key,value)->{
            List<String> versionList=this.getHistoryVersion(busiNo,busiNode,key);
            log.info("{}+{}+文件类型{}+版本:{}",busiNo,busiNode,key,versionList.toString());
            value.forEach(file->{
                file.setHistoryVersion(String.valueOf(versionList.size()));
                file.setFileStatus(FileStatusEnum.STANDARD.getCode());
                this.updateById(file);
            });
        });
    }

    /**
     * @Description: 收到退回消息时，修改进件库文件状态
     * @Author: fangchenliang
     * @Date: 2020/8/6 22:47
     * @Param: [contractNo, attachmentIdList]
     * @Return: void
     */
    public void updateFileStatusForLoan(String contractNo,List<String> attachmentIdList){
        attachmentIdList.forEach(id->{
            List<ComAttachmentFile> fileList=this.list(Wrappers.<ComAttachmentFile>query().lambda()
                    .eq(ComAttachmentFile::getBusiNo,contractNo)
                    .eq(ComAttachmentFile::getAttachmentCode,id)
                    .eq(ComAttachmentFile::getHistoryVersion,"0")
                    .eq(ComAttachmentFile::getFileStatus,FileStatusEnum.STANDARD.getCode()));
            fileList.forEach(file->{
                file.setFileStatus(FileStatusEnum.NOTSTANDARD.getCode());
                this.updateById(file);
            });
        });
    }

    /**
     * 根据场景取最新合同模板
     * @param page
     * @param condition
     * @return
     */
    @Override
    public IPage<List<ComAttachmentFile>> getComAttachMentFileByPage(Page page, ImageCondition condition) {
        return this.baseMapper.getComAttachMentFileByPage(page, condition);
    }

    /**
     * 旋转文件
     * @param md5
     * @param fileName
     * @param fileType
     * @param degree
     * @return
     */
    public JSONObject revolveFile(String md5, String fileName,String fileType,int degree){
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", getAuthorization());
        byte[] fileByte = imageStoreApiFeign.downFile(md5,  gwtFastdfsProperties.getSceneId(), fileName, IsViewEnum.download.getCode(), null, headers);
        InputStream in=new ByteArrayInputStream(fileByte);
        Img img= Img.from(in);
        img.rotate(degree);
        BufferedImage bufferedImage=img.getImg();
        String tmpPath = fileProperties.getTempDir() + File.separator + fileName;
        File storeFile =new File(tmpPath);
        try {
            ImageIO.write(bufferedImage, fileType, storeFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        MultipartFile file = imageUtil.getMulFile(storeFile, fileName);
        JSONObject json = imageStoreApiFeign.storeFile( gwtFastdfsProperties.getSceneId(),null,file,headers);
        FileUtil.del(tmpPath);
        return json;
    }

    /**
     * @Description:单个文件下载返回文件流
     * @Author: fangchenliang
     * @Date: 2020/8/17 18:44
     * @Param:MD5
     * @Return:byte[]
     */
    public byte[] downloadFileBytes(String md5){

        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", getAuthorization());
        byte[] fileByte = imageStoreApiFeign.downFile(md5, gwtFastdfsProperties.getSceneId(), "", IsViewEnum.download.getCode(), null, headers);
        return fileByte;
    }

    /**
     * 获取最新合同模板数据
     * @param attachmentCode
     * @param busiNo
     * @param belongNo
     * @return
     */
    public ComAttachmentFile getNewAttachmentFile(String attachmentCode, String busiNo, String belongNo){

        List<ComAttachmentFile> fileList = list(Wrappers.<ComAttachmentFile>query().lambda()
                .eq(ComAttachmentFile::getAttachmentCode, attachmentCode)
                .eq(ComAttachmentFile::getBusiNo, busiNo)
                .eq(ComAttachmentFile::getBelongNo, belongNo)
                .orderByDesc(ComAttachmentFile::getUploadTime));
        Assert.isTrue(CollUtil.isNotEmpty(fileList), "获取远端模板数据失败，请检查用来获取远端模板的参数");
        ComAttachmentFile comAttachmentFile = fileList.get(0);
        return comAttachmentFile;
    }
}
